home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #27 (Dec 87) / c daisy printer driver / PDEF4.c < prev    next >
C/C++ Source or Header  |  1987-09-29  |  15KB  |  510 lines

  1. /*
  2.  * PDEF4.c.
  3.  *
  4.  * Generic daisy/dot matrix text printer driver for the Macintosh.
  5.  * Earle R. Horton        August 31, 1987
  6.  * All rights reserved.
  7.  *
  8.  *      This module contains the code for validating, creating,
  9.  * and modifying print records.
  10.  */
  11. /*
  12.  * This module is to be placed into a code resource project using LightspeedC,
  13.  * version 2.01 or greater.  The project is to be made into PDEF resource
  14.  * number 4.  All of the code up to and including the first illegal instruction
  15.  * is to be stripped off, so that the PDEF will have the standard format for
  16.  * resources of this type.  Switch statements cannot be used, since LightspeedC
  17.  * compiles them into separate code which is added to the beginning of the
  18.  * code resource, before our standard header.  I do not know at this point
  19.  * which types of flow control constructs are safe, but I have determined by
  20.  * disassembly that the following will produce useable code:
  21.  *        if, if/else blocks
  22.  *        gotos
  23.  *
  24.  * Instructions, or "How I did it."
  25.  *     Create from this module a code resource of type 'pdef' ID 4.
  26.  *    Run the program utils.c to make it into PDEF ID 4 and to strip
  27.  *    off the standard header.
  28.  */
  29.  
  30. #include <DialogMgr.h>
  31. #include <EventMgr.h>
  32. #include "prglobals.h"
  33. #define STYLEDIALOG    (0xE000)
  34. #define JOBDIALOG    (0xE001)
  35. #define XTRA    24    /* Six extra longs for our use. */
  36. #define DLGSIZE ((long)(sizeof(TPrDlg) + XTRA))
  37. #define    TPSIZE    ((long)(sizeof(TPrint)))
  38. /* Items we handle in the job and style dialogs. */
  39. #define CANCELITEM    2
  40. #define    CPI10BUTTON    4
  41. #define    CPI12BUTTON    5
  42. #define    CPI15BUTTON    6
  43. #define    STRAIGHTUPITEM    7
  44. #define    SIDEWAYSITEM    8
  45. #define ALLBUTTON    5
  46. #define    RANGEBUTTON    6
  47. #define    FROMNUM        7
  48. #define    TONUM        9
  49. #define    COPIES        11
  50. #define    FANBUTTON    13
  51. #define    SHEETBUTTON    14
  52.  
  53. pascal void    MyPrintDefault();    /* Fill a print record with defaults. */
  54. pascal Boolean    MyPrStlDialog();    /* Conduct printer style dialog. */
  55. pascal Boolean    MyPrJobDialog();    /* Conduct printer job dialog. */
  56. pascal TPPrDlg    MyPrStlInit();        /* Set up the style dialog. */
  57. pascal TPPrDlg    MyPrJobInit();        /* Set up the job dialog. */
  58. pascal Boolean     MyPrDlgMain();        /* Printing dialog supervisor function. */
  59. pascal Boolean    MyPrValidate();        /* Validate/update a print record. */
  60. pascal void    MyPrJobMerge();        /* Copy a job subrecord. */
  61. pascal Boolean    MyFilter();        /* Filter dialog events. */
  62. pascal void    HandleStyleItems();    /* Handle Style Items. */
  63. pascal void    HandleJobItems();    /* Handle Job Items. */
  64. TPPrDlg     TPPrDlgallocate();
  65. void        pushradiobutton();
  66. int        NumToString(),StringToNum();
  67. Boolean        Valid();
  68. void        mkDefault();
  69. void        free();
  70. main()
  71. {
  72.     asm{
  73.         dc.w    ILLEGAL        ;;  So I can find it...
  74.         jmp    MyPrintDefault
  75.         jmp    MyPrStlDialog
  76.         jmp    MyPrJobDialog
  77.         jmp    MyPrStlInit
  78.         jmp    MyPrJobInit
  79.         jmp    MyPrDlgMain
  80.         jmp    MyPrValidate
  81.         jmp    MyPrJobMerge
  82.  
  83.     }
  84. }
  85. /* 
  86.  * This function fills a print record with defaults.  The default values
  87.  * are stored in the Printer resource file, in PREC 0.  This is easy.  Then
  88.  * we check the fields of the print record for anything obviously illegal.
  89.  * If the default print record contains stuff that is bad, then we correct
  90.  * it and update the copy in the printer resource file.  This should never
  91.  * happen, but some wise guy with a copy of ResEdit and more brains than
  92.  * sense may think he knows more than we do.
  93.  */
  94. pascal void    MyPrintDefault(hPrint)
  95. THPrint hPrint;
  96. {
  97. THPrint    thedefault;
  98.     thedefault = (THPrint)(GetResource('PREC',0));
  99.     if(thedefault == nil){
  100.         mkDefault(hPrint);
  101.     }
  102.     else{
  103.         LoadResource(thedefault);
  104.         if(MyPrValidate(thedefault)) {
  105.             ChangedResource(thedefault);
  106.             WriteResource(thedefault);
  107.         }
  108.         **hPrint = **thedefault;    /* What the hell. */
  109.     }
  110. }
  111. pascal Boolean    MyPrStlDialog(hPrint)    /* Conduct printer style dialog. */
  112. THPrint hPrint;
  113. {
  114.     return(MyPrDlgMain(hPrint,MyPrStlInit));
  115. }
  116. pascal Boolean    MyPrJobDialog(hPrint)    /* Conduct printer job dialog. */
  117. THPrint hPrint;
  118. {
  119.     return(MyPrDlgMain(hPrint,MyPrJobInit));
  120. }
  121. /* 
  122.  * The style dialog initializer.
  123.  */
  124. pascal     TPPrDlg    MyPrStlInit(hPrint)
  125. THPrint hPrint;
  126. {
  127. TPPrDlg    tp;
  128.     tp = TPPrDlgallocate();
  129.     (GetNewDialog(STYLEDIALOG,tp,-1));
  130.     if((*hPrint)->prInfo.iDev == IDEV10)
  131.         pushradiobutton(tp,CPI10BUTTON,CPI10BUTTON,CPI15BUTTON);
  132.     else if((*hPrint)->prInfo.iDev == IDEV12)
  133.         pushradiobutton(tp,CPI12BUTTON,CPI10BUTTON,CPI15BUTTON);
  134.     else if((*hPrint)->prInfo.iDev == IDEV15)
  135.         pushradiobutton(tp,CPI15BUTTON,CPI10BUTTON,CPI15BUTTON);
  136.     pushradiobutton(tp,STRAIGHTUPITEM,STRAIGHTUPITEM,SIDEWAYSITEM);
  137.     tp->pFltrProc = (ProcPtr)MyFilter;
  138.     tp->pItemProc = (ProcPtr)HandleStyleItems;
  139.     tp->hPrintUsr = hPrint;
  140.  
  141.     return(tp);
  142. }
  143. /* 
  144.  * The job dialog initializer.
  145.  */
  146. pascal TPPrDlg    MyPrJobInit(hPrint)
  147. THPrint hPrint;
  148. {
  149. TPPrDlg        tp;
  150. int         thenum;
  151. Handle        theitem;
  152. Rect        thebox;
  153. Str36        title;
  154.     tp = TPPrDlgallocate();
  155.     (GetNewDialog(JOBDIALOG,tp,-1));
  156.     pushradiobutton(tp,ALLBUTTON,ALLBUTTON,RANGEBUTTON);
  157.     if( (*hPrint)->prStl.feed == feedCut)
  158.         pushradiobutton(tp,SHEETBUTTON,FANBUTTON,SHEETBUTTON);
  159.     else    
  160.         pushradiobutton(tp,FANBUTTON,FANBUTTON,SHEETBUTTON);
  161.     GetDItem(tp,FROMNUM,&thenum,&theitem,&thebox);
  162.     thenum = (*hPrint)->prJob.iFstPage;
  163.     NumToString((long)thenum,title);
  164.     SetIText(theitem,title);
  165.     
  166.     GetDItem(tp,TONUM,&thenum,&theitem,&thebox);
  167.     thenum = (*hPrint)->prJob.iLstPage;
  168.     NumToString((long)thenum,title);
  169.     SetIText(theitem,title);
  170.  
  171.     GetDItem(tp,COPIES,&thenum,&theitem,&thebox);
  172.     thenum = (*hPrint)->prJob.iCopies;
  173.     NumToString((long)thenum,title);
  174.     SetIText(theitem,title);
  175.  
  176.     tp->pFltrProc = (ProcPtr)MyFilter;
  177.     tp->pItemProc = (ProcPtr)HandleJobItems;
  178.     tp->hPrintUsr = hPrint;
  179.     return(tp);
  180. }
  181. pascal Boolean     MyPrDlgMain(hPrint,pDlgInit)
  182.                 /* Printing dialog supervisor function. */
  183.                 /* Reference: Macintosh Technical Note  */
  184.                 /* 95.  Good luck! */
  185. THPrint hPrint;
  186. ProcPtr pDlgInit;
  187. {
  188. TPPrDlg    tp;
  189. WindowPtr tempport;
  190. int     donetype,itemhit;
  191. Handle    doneitem;
  192. Rect    donebox;
  193. ProcPtr    itemproc;
  194.     asm{
  195.         subq.l    #4,a7        ;;  Room for function return.
  196.         move.l    hPrint,-(a7)    ;;  Pass handle to print record.
  197.         move.l    pDlgInit,a0    ;;  Get address of dialog init routine.
  198.         jsr    (a0)        ;;  It's a "Pascal" routine.
  199.         move.l    (a7)+,tp    ;;  Pop return value.
  200.     }
  201.     itemproc = tp->pItemProc;
  202.     tp->fDone = FALSE;
  203.     tp->fDoIt = FALSE;
  204.     GetPort(&tempport);
  205.     SetPort(tp);
  206.     ShowWindow(tp);
  207.     GetDItem(tp,DONEITEM,&donetype,&doneitem,&donebox);
  208.     PenSize(3,3);
  209.     InsetRect(&donebox,-4,-4);
  210.     FrameRoundRect(&donebox,16,16);    
  211.     while(!(tp->fDone)){
  212.         ModalDialog(tp->pFltrProc,&itemhit);
  213. /*
  214.  * Reverse parameters on the call to pItemProc.  The application is allowed 
  215.  * to trap our pItemProc and insert its own, so we must use the Pascal 
  216.  * calling conventions here.  Programming novices can use the LightspeedC™ 
  217.  * CallPascal library if they want.  You will have to be careful if you do
  218.  * this to make sure the library is linked AFTER the module containing these
  219.  * functions, or you won't get the PDEF resource header right.
  220.  */
  221.          asm{
  222.              move.l    tp,-(a7)
  223.              move.w    itemhit,-(a7)
  224.              move.l    itemproc,a0
  225.              jsr    (a0)
  226.          }
  227.     }
  228.     SetPort(tempport);
  229.     CloseDialog(tp);
  230.     free(tp);
  231.     if(tp->fDoIt) (void)MyPrValidate(hPrint);
  232.     return(tp->fDoIt);
  233. }
  234. /*
  235.  * Validate/update a print record.  Check all the fields for compatibility with
  236.  * our driver.  This is a three stage process.  First, we check all fields to
  237.  * see whether they are within the bounds which our driver can handle.  If 
  238.  * they are, we return FALSE (no change).  If not, we obtain a copy of the
  239.  * current default values from the printer resource file.  Then we inspect
  240.  * these to see if they are valid.  If the default values in the printer
  241.  * resource file are valid, we use them, update the user's print record,
  242.  * and return TRUE (changed).  Otherwise, we fall back on default values
  243.  * which we store in the code here.  This three stage process provides some
  244.  * protection against the user who attempts to adjust the print record using
  245.  * a resource editor, and screws up.
  246.  */
  247. pascal Boolean    MyPrValidate(hPrint)    /* Validate/update a print record. */
  248. THPrint hPrint;
  249. {
  250. THPrint    thedefault;
  251.     if(Valid(hPrint)) return FALSE;
  252.     else{
  253.         thedefault = (THPrint)(GetResource('PREC',0));
  254.         LoadResource(thedefault);
  255.         if(thedefault == nil || !Valid(thedefault)) mkDefault(hPrint);
  256.         else{
  257.             **hPrint = **thedefault;
  258.         }
  259.         return TRUE;
  260.     }
  261. }
  262. pascal void    MyPrJobMerge(hPrintSrc,hPrintDst)
  263. /*
  264.  * Copy a job subrecord.  Update the destination record's printer information,
  265.  * band information, and paper rectangle, based on information in the job
  266.  * subrecord.
  267.  */
  268. THPrint hPrintSrc,hPrintDst;
  269. {
  270.     (*hPrintDst)->prInfo.iDev = (*hPrintSrc)->prInfo.iDev;
  271.     (*hPrintDst)->prJob = (*hPrintSrc)->prJob;
  272.     (*hPrintDst)->prXInfo = (*hPrintSrc)->prXInfo;
  273.     (*hPrintDst)->rPaper = (*hPrintSrc)->rPaper;
  274.     (*hPrintDst)->prInfo = (*hPrintSrc)->prInfo;
  275.     (*hPrintDst)->prInfoPT = (*hPrintSrc)->prInfoPT;
  276. }
  277. pascal Boolean    MyFilter(thedialog,theEvent,itemhit)
  278. DialogPtr    thedialog;
  279. EventRecord    *theEvent;
  280. int        *itemhit;
  281. {
  282.     if(theEvent->what == keyDown && 
  283.         (theEvent->message & charCodeMask) == 13){
  284.             *itemhit = 1;
  285.             return TRUE;
  286.     }
  287.     return    FALSE;
  288. }
  289. /* 
  290.  * The next routine handles the style dialog.  Two possibilities exist.
  291.  * If the cancel button is hit, then we signal quit.  The print record
  292.  * is not changed.
  293.  * If the done button is hit, we validate the user's print record.
  294.  * (MyPrDlgMain() calls MyPrValidate() to do this.)
  295.  * We use three radio buttons to determine the number of characters
  296.  * per inch (resolution), and two to determine paper orientation.
  297.  */
  298. pascal void    HandleStyleItems(tp,itemhit)
  299. TPPrDlg    tp;
  300. int    itemhit;
  301. {
  302. int    thenum;
  303. Handle    theitem;
  304. Rect    thebox;
  305.     if(itemhit >= CPI10BUTTON && itemhit <= CPI15BUTTON)
  306.         pushradiobutton(tp,itemhit,CPI10BUTTON,CPI15BUTTON);
  307.     else if(itemhit >= STRAIGHTUPITEM && itemhit <= SIDEWAYSITEM)
  308.         pushradiobutton(tp,itemhit,STRAIGHTUPITEM,SIDEWAYSITEM);
  309.     else if(itemhit == DONEITEM){
  310.         TPrint Print;
  311.         TPPrint pPrint;
  312.         pPrint = &Print;
  313.         mkDefault(&pPrint);
  314.         (*tp->hPrintUsr)->iPrVersion = Print.iPrVersion;
  315.         (*tp->hPrintUsr)->prInfo = Print.prInfo;
  316.         (*tp->hPrintUsr)->prXInfo = Print.prXInfo;
  317.         (*tp->hPrintUsr)->rPaper = Print.rPaper;
  318.         (*tp->hPrintUsr)->prStl = Print.prStl;
  319.         (*tp->hPrintUsr)->prInfoPT = Print.prInfoPT;
  320.         GetDItem(tp,CPI10BUTTON,&thenum,&theitem,&thebox);
  321.         if(GetCtlValue(theitem) == 1){
  322.             (*tp->hPrintUsr)->prInfo.iDev = IDEV10;
  323.         }
  324.         GetDItem(tp,CPI12BUTTON,&thenum,&theitem,&thebox);
  325.         if(GetCtlValue(theitem) == 1){
  326.             (*tp->hPrintUsr)->prInfo.iDev = IDEV12;
  327.         }
  328.         GetDItem(tp,CPI15BUTTON,&thenum,&theitem,&thebox);
  329.         if(GetCtlValue(theitem) == 1){
  330.             (*tp->hPrintUsr)->prInfo.iDev = IDEV15;
  331.         }
  332.         GetDItem(tp,SIDEWAYSITEM,&thenum,&theitem,&thebox);
  333.         if(GetCtlValue(theitem) == 1){
  334.             int temp;
  335.             flipRect(&(*tp->hPrintUsr)->prInfo.rPage);
  336.             flipRect(&(*tp->hPrintUsr)->rPaper);
  337.             flipRect(&(*tp->hPrintUsr)->prInfoPT.rPage);
  338.             temp = (*tp->hPrintUsr)->prStl.iPageV;
  339.             (*tp->hPrintUsr)->prStl.iPageV = 
  340.                 (*tp->hPrintUsr)->prStl.iPageH;
  341.             (*tp->hPrintUsr)->prStl.iPageH = temp;
  342.         }
  343.         tp->fDone = TRUE;
  344.         tp->fDoIt = TRUE;
  345.     }
  346.     else if (itemhit == CANCELITEM){
  347.         tp->fDone = TRUE;
  348.         tp->fDoIt = FALSE;
  349.     }
  350. }
  351. pascal void    HandleJobItems(tp,itemhit)
  352. TPPrDlg    tp;
  353. int        itemhit;
  354. {
  355. int         thenum;
  356. long        thelong;
  357. Handle        numitem;
  358. Rect        numbox;
  359. Str36        title;
  360.     if(itemhit == DONEITEM){        /* NO SWITCHES! */
  361.         tp->fDone = TRUE;        /* At least until I get a */
  362.         tp->fDoIt = TRUE;        /* better compiler. */
  363.         GetDItem(tp,ALLBUTTON,&thenum,&numitem,&numbox);
  364.         if(GetCtlValue(numitem) == 1){
  365.             (*(tp->hPrintUsr))->prJob.iFstPage = iPrPgFst;
  366.             (*(tp->hPrintUsr))->prJob.iLstPage = iPrPgMax;
  367.         }
  368.         else{
  369.             GetDItem(tp,FROMNUM,&thenum,&numitem,&numbox);
  370.             GetIText(numitem,&title[0]);
  371.             StringToNum(&title[0],&thelong);
  372.             (*(tp->hPrintUsr))->prJob.iFstPage = thelong;    
  373.             GetDItem(tp,TONUM,&thenum,&numitem,&numbox);
  374.             GetIText(numitem,&title[0]);
  375.             StringToNum(&title[0],&thelong);
  376.             (*(tp->hPrintUsr))->prJob.iLstPage = thelong;    
  377.         }
  378.             GetDItem(tp,COPIES,&thenum,&numitem,&numbox);
  379.             GetIText(numitem,&title[0]);
  380.             StringToNum(&title[0],&thelong);
  381.             (*(tp->hPrintUsr))->prJob.iCopies = thelong;
  382.         GetDItem(tp,SHEETBUTTON,&thenum,&numitem,&numbox);
  383.         if(GetCtlValue(numitem) == 1){
  384.             (*(tp->hPrintUsr))->prStl.feed = feedCut;
  385.         }
  386.         else (*(tp->hPrintUsr))->prStl.feed = feedFanfold;
  387.     }
  388.     else if (itemhit == CANCELITEM){
  389.         tp->fDone = TRUE;
  390.     }
  391.     else if (itemhit == SHEETBUTTON){
  392.         pushradiobutton(tp,SHEETBUTTON,FANBUTTON,SHEETBUTTON);
  393.         (*(tp->hPrintUsr))->prStl.feed = feedCut;
  394.     }
  395.     else if (itemhit == FANBUTTON){
  396.         pushradiobutton(tp,FANBUTTON,FANBUTTON,SHEETBUTTON);
  397.         (*(tp->hPrintUsr))->prStl.feed = feedFanfold;
  398.     }
  399.     else if (itemhit == ALLBUTTON){
  400.         pushradiobutton(tp,ALLBUTTON,ALLBUTTON,RANGEBUTTON);
  401.     }
  402.     else if (itemhit == RANGEBUTTON){
  403.         pushradiobutton(tp,RANGEBUTTON,ALLBUTTON,RANGEBUTTON);
  404.     }
  405. }
  406. TPPrDlg TPPrDlgallocate()
  407. {
  408. TPPrDlg        thepointer;
  409.     asm{
  410.         move.l    #DLGSIZE,d0
  411.         NewPtr
  412.         move.l    a0,thepointer
  413.     }
  414.     if(thepointer == nil){    /* We're in deep shit now! */
  415.         asm{
  416.             move.w    #25,d0
  417.             SysError        ;;  SysError
  418.         }
  419.     }
  420.     return(thepointer);
  421. }
  422. void pushradiobutton(thedialog,itemhit,first,last)    /* push a radio Button */
  423. DialogPtr thedialog;                /* set itemhit, unset  */
  424. int itemhit,first,last;                /* all others in range */
  425. {
  426.       int itemtype,i;
  427.       Handle itemhandle;            /* Does check boxes, too. */
  428.       Rect itemrect;
  429.     if(first ==0) return;
  430.     for(i=first-1;last-i++;){
  431.         GetDItem(thedialog,i,&itemtype,&itemhandle,&itemrect);
  432.         if(i == itemhit) SetCtlValue(itemhandle,1);
  433.         else SetCtlValue(itemhandle,0);
  434.     }
  435. }
  436. NumToString(thenum,thestring)
  437. long    thenum;
  438. char    *thestring;
  439. {
  440.     asm{
  441.         move.l    thestring,a0
  442.         move.l    thenum,d0
  443.         move.w    #0,-(a7)
  444.         Pack7
  445.     }
  446. }
  447. StringToNum(thestring,thenum)
  448. char    *thestring;
  449. long    *thenum;
  450. {
  451.     asm{
  452.         move.l    thestring,a0
  453.         move.w    #1,-(a7)
  454.         Pack7
  455.         move.l    thenum,a0
  456.         move.l    d0,(a0)
  457.     }
  458. }
  459. /*
  460.  * This function answers the question:  Can we possibly use this print
  461.  * record?
  462.  */
  463. Boolean    Valid(hPrint)
  464. THPrint hPrint;
  465. {
  466. if    (((*hPrint)->iPrVersion != VERSION)
  467.      || ((*hPrint)->prInfo.iDev != IDEV12 &&
  468.          (*hPrint)->prInfo.iDev != IDEV10 &&
  469.          (*hPrint)->prInfo.iDev != IDEV15)
  470.      || ((*hPrint)->prInfo.iVRes != VREZZ)
  471.      || ((*hPrint)->prInfo.iHRes != HREZZ12)
  472.      || ((*hPrint)->prInfo.rPage.top !=0 ||
  473.          (*hPrint)->prInfo.rPage.left !=0)
  474.      || ((*hPrint)->rPaper.right - 
  475.          (*hPrint)->rPaper.left > 11 * HREZZ12)    
  476.      || ((*hPrint)->rPaper.bottom -
  477.          (*hPrint)->rPaper.top > 11 * VREZZ)    
  478.      || ((*hPrint)->prStl.feed != feedCut && 
  479.          (*hPrint)->prStl.feed != feedFanfold)    
  480.      || ((*hPrint)->prJob.bJDocLoop != bDraftLoop))    
  481.  
  482.     return FALSE;
  483.  
  484. else    return    TRUE;
  485. }
  486. void free(ptr)
  487. char    *ptr;
  488. {
  489.     asm{
  490.         move.l    ptr,a0
  491.         DisposPtr
  492.     }
  493. }
  494. flipRect(rect)
  495. Rect    *rect;
  496. {
  497.     asm{
  498.         move.l    rect,a0
  499.         move.l    (a0),d0
  500.         swap    d0        ;; swap top, left
  501.         move.l    d0,(a0)+
  502.         move.l    (a0),d0
  503.         swap    d0        ;; swap bottom, right
  504.         move.l    d0,(a0)
  505.     }
  506. }
  507.         
  508. #include "mkDefault.c"
  509.  
  510.